home *** CD-ROM | disk | FTP | other *** search
- /* $Id: game.c,v 1.1.1.1 1993/06/21 11:11:59 anjo Exp $
- *
- * File game.c
- * Part of ChessBase utilities file format (CBUFF)
- * Author Anjo Anjewierden, anjo@swi.psy.uva.nl
- * Purpose Representation of a chess game
- * Works with GNU CC 2.4.5
- *
- * Notice Copyright (c) 1993 Anjo Anjewierden
- *
- * History 09/06/93 (Created)
- * 03/11/93 (Last modified)
- */
-
-
- /*------------------------------------------------------------
- * Directives
- *------------------------------------------------------------*/
-
- #include "cbuff.h"
-
-
- /*------------------------------------------------------------
- * Definitions
- *------------------------------------------------------------*/
-
- static void requireHeaderGame(Game);
- static void requireMovesGame(Game);
-
-
- /*------------------------------------------------------------
- * Initialisation
- *------------------------------------------------------------*/
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node newGame
- @deftypefun Game newGame ()
- Returns a new instance of a (chess) game structure. The instance
- returned is initialised.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- Game
- newGame()
- { Game g;
-
- g = alloc(sizeof(struct game));
- g->cbGame = NULL;
- g->firstMove = NULL;
- g->position = NULL;
-
- resetGame(g);
-
- return g;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node freeGame
- @deftypefun void freeGame (Game @var{g})
- Unallocates the game.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- void
- freeGame(Game g)
- { resetGame(g);
- unalloc(g);
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node resetGame
- @deftypefun void resetGame (Game @var{g})
- Resets the game such that it may be used to load another.
- @code{resetGame} is conceptually identical to:
- @example
- freeGame(g);
- g = newGame();
- @end example
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- void
- resetGame(Game g)
- { if (g->firstMove)
- { freeMove(g->firstMove);
- g->firstMove = NULL;
- }
- if (g->cbGame)
- { freeCbGame(g->cbGame);
- g->cbGame = NULL;
- }
- if (g->position)
- { freePosition(g->position);
- g->position = NULL;
- }
- g->number = 0L;
- g->database = NULL;
- g->flags = 0;
- g->players[0] = '\0';
- g->source[0] = '\0';
- g->year = 0;
- g->result = 0;
- g->eloWhite = 0;
- g->eloBlack = 0;
- g->eco[0] = '\0';
- g->moves = 0;
- g->plies = 0;
- g->place = NullString;
- g->event = NullString;
- g->annotator = NullString;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node initialiseGame
- @deftypefun bool initialiseGame (Game @var{g}, long @var{number}, CBase @var{database})
- Initialises a game to be read from an existing ChessBase database. The
- @var{number} is the game number relative to the @var{database}.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- bool
- initialiseGame(Game g, long number, CBase database)
- { if (g->flags & GAME_INIT_OK)
- resetGame(g);
-
- if (number < 1 || number > database->noGames)
- { setError(ERR_GAME_NUMBER_OUT_OF_RANGE);
- return FALSE;
- }
-
- g->number = number;
- g->database = database;
- g->flags |= GAME_INIT_OK;
-
- return TRUE;
- }
-
-
- /*------------------------------------------------------------
- * Accessing game properties
- *------------------------------------------------------------*/
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node flags2Bit6GameP
- @deftypefun bool flags2Bit6GameP (Game @var{g})
- Succeeds if bit 6 of the flags2 field of the game header is set. This
- bit apparently decides on the character set being used, but is still a
- slightly mysterious. At the moment, only games that this bit set print
- all comments correctly.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- bool
- flags2Bit6GameP(Game g)
- { return (g->flags & GAME_FLAGS2_BIT6 ? TRUE : FALSE);
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node fullGameP
- @deftypefun bool fullGameP (Game @var{g})
- Succeeds if the game is a complete game (starting from the initial position),
- and fails if a starting position is provided with the game.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- bool
- fullGameP(Game g)
- { requireHeaderGame(g);
- return (g->flags & GAME_INITIAL_POSITION ? TRUE : FALSE);
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node deletedGameP
- @deftypefun bool deletedGameP (Game @var{g})
- Succeeds if the game has been logically deleted from the database. A
- game is fysically deleted by the @file{cbfresh} utility provided with
- ChessBase.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- bool
- deletedGameP(Game g)
- { requireHeaderGame(g);
- return (g->flags & GAME_DELETED ? TRUE : FALSE);
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node markedGameP
- @deftypefun bool markedGameP (Game @var{g})
- Succeeds if the game has been marked in the database. The meaning of a
- marked game is up to the user. It presumably means the game is more
- interesting than the unmarked games in the database.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- bool
- markedGameP(Game g)
- { requireHeaderGame(g);
- return (g->flags & GAME_MARKED ? TRUE : FALSE);
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node containsCommentsGameP
- @deftypefun bool containsCommentsGameP (Game @var{g})
- Succeeds if the game contains comments for at least one of the moves.
- Examples of comments are ``@code{!!}'', ``@code{+-}'' and ``This is
- a great move''.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- bool
- containsCommentsGameP(Game g)
- { requireHeaderGame(g);
- if (g->cbGame->commentLength)
- return TRUE;
- return FALSE;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node containsVariationsGameP
- @deftypefun bool containsVariationsGameP (Game @var{g})
- Succeeds if the game contains at least one variation.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- bool
- containsVariationsGameP(Game g)
- { requireHeaderGame(g);
- if (g->plies < g->cbGame->movesLength)
- return TRUE;
- return FALSE;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node getPlayersGame
- @deftypefun {char *} getPlayersGame (Game @var{g})
- Returns the names of the players of the game. When the application
- wants to manipulate the players, a copy of the @w{@code{char *}}
- returned should be made.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- char *
- getPlayersGame(Game g)
- { requireHeaderGame(g);
- return g->players;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node getSourceGame
- @deftypefun {char *} getSourceGame (Game @var{g})
- Returns the names of the source of the game. When the application
- wants to manipulate the source, a copy of the @w{@code{char *}}
- returned should be made.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- char *
- getSourceGame(Game g)
- { requireHeaderGame(g);
- return g->source;
- }
-
-
- char *
- getPlaceGame(Game g)
- { requireHeaderGame(g);
- return normalisePlace(g->source);
- }
-
-
- char *
- getAnnotatorGame(Game g)
- { requireHeaderGame(g);
- return g->annotator;
- }
-
-
- char *
- getEventGame(Game g)
- { requireHeaderGame(g);
- return g->event;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node containsPlayerNamesGameP
- @deftypefun bool containsPlayerNamesGameP (Game @var{g})
- Succeeds if the game contains the names of the players. The heuristic
- is to check whether the players field contains at least one hyphen.
- Note that some games may actually be an overview of a certain opening,
- where the players field is used to name the opening.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- bool
- containsPlayerNamesGameP(Game g)
- { requireHeaderGame(g);
- if (strchr(g->players, '-'))
- return TRUE;
- return FALSE;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node getWhiteGame
- @deftypefun {char *} getWhiteGame (Game @var{g})
- Returns the name of the player with the white pieces. The @w{@code{char
- *}} is allocated statically. A return value of @code{NULL} means that
- the information could not be extracted.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- static bool
- substituteHyphen(char *s, char *pattern)
- { char *t;
-
- for (t=s; *t; t++)
- { if (strhead(t, pattern))
- { int l = strlen(pattern);
-
- while (l--)
- { if (*t == '-')
- *t = ' ';
- t++;
- }
- return TRUE;
- }
- }
- return FALSE;
- }
-
-
- char *
- getWhiteGame(Game g)
- { static char white[MAX_NAME_SIZE+1];
- char *s;
-
- requireHeaderGame(g);
- again:
- s = strchr(g->players, '-');
- if (s && s == strrchr(g->players, '-'))
- { *s = '\0';
- strcpy(white, g->players);
- *s = '-';
- return normalisePlayer(white);
- }
- if (s && strrchr(g->players, '-')) /* At least two hyphens */
- {
- if (substituteHyphen(g->players, "Al-Khateeb")) goto again;
- if (substituteHyphen(g->players, "Al-Mansouri")) goto again;
- if (substituteHyphen(g->players, "Al-Modiahki")) goto again;
- if (substituteHyphen(g->players, "Ana-L")) goto again;
- if (substituteHyphen(g->players, "Ana-Maria")) goto again;
- if (substituteHyphen(g->players, "Anna-Maria")) goto again;
- if (substituteHyphen(g->players, "Anne-Marie")) goto again;
- if (substituteHyphen(g->players, "Armel-David")) goto again;
- if (substituteHyphen(g->players, "Astolfi-Perez")) goto again;
- if (substituteHyphen(g->players, "Badea-Takacs")) goto again;
- if (substituteHyphen(g->players, "Bazaj-Bocka")) goto again;
- if (substituteHyphen(g->players, "Bert-Steffen")) goto again;
- if (substituteHyphen(g->players, "Bos-Swiecik")) goto again;
- if (substituteHyphen(g->players, "Brilla-Banfalvi")) goto again;
- if (substituteHyphen(g->players, "Brinck-Claussen")) goto again;
- if (substituteHyphen(g->players, "Carl-Magnus")) goto again;
- if (substituteHyphen(g->players, "Chekhova-Kostina")) goto again;
- if (substituteHyphen(g->players, "Chin-Hoe")) goto again;
- if (substituteHyphen(g->players, "Chong-Ghee")) goto again;
- if (substituteHyphen(g->players, "Cruz-Lopez")) goto again;
- if (substituteHyphen(g->players, "Cuevas-Rodriguez")) goto again;
- if (substituteHyphen(g->players, "Dan-Robert")) goto again;
- if (substituteHyphen(g->players, "Donaldson-Akhmilovskaya")) goto again;
- if (substituteHyphen(g->players, "Dus-Chotimirski")) goto again;
- if (substituteHyphen(g->players, "Erenska-Radzewska")) goto again;
- if (substituteHyphen(g->players, "Eric-Andre")) goto again;
- if (substituteHyphen(g->players, "Esko-Matti")) goto again;
- if (substituteHyphen(g->players, "Fauland-Borek")) goto again;
- if (substituteHyphen(g->players, "Flear-Leroy")) goto again;
- if (substituteHyphen(g->players, "Foong-Yin")) goto again;
- if (substituteHyphen(g->players, "Fries-Nielsen")) goto again;
- if (substituteHyphen(g->players, "Frolich-Dill")) goto again;
- if (substituteHyphen(g->players, "Garcia-Palermo")) goto again;
- if (substituteHyphen(g->players, "Gerd-Peter")) goto again;
- if (substituteHyphen(g->players, "Gerrit-Hans")) goto again;
- if (substituteHyphen(g->players, "Gert-Jan")) goto again;
- if (substituteHyphen(g->players, "Gian-Thier")) goto again;
- if (substituteHyphen(g->players, "Gustav-Schutz")) goto again;
- if (substituteHyphen(g->players, "Hajkova-Maskova")) goto again;
- if (substituteHyphen(g->players, "Hans-Elmar")) goto again;
- if (substituteHyphen(g->players, "Hans-Georg")) goto again;
- if (substituteHyphen(g->players, "Hans-Gunther")) goto again;
- if (substituteHyphen(g->players, "Hans-Hilmar")) goto again;
- if (substituteHyphen(g->players, "Hans-Hubert")) goto again;
- if (substituteHyphen(g->players, "Hans-J")) goto again;
- if (substituteHyphen(g->players, "Hans-Otto")) goto again;
- if (substituteHyphen(g->players, "Hans-Peter")) goto again;
- if (substituteHyphen(g->players, "Hans-U")) goto again;
- if (substituteHyphen(g->players, "Har-Zvi")) goto again;
- if (substituteHyphen(g->players, "Hartung-Nielsen")) goto again;
- if (substituteHyphen(g->players, "Heine-Nielsen")) goto again;
- if (substituteHyphen(g->players, "Heinz-Dieter")) goto again;
- if (substituteHyphen(g->players, "Heinz-Jurg")) goto again;
- if (substituteHyphen(g->players, "Heinz-Wilhelm")) goto again;
- if (substituteHyphen(g->players, "Hoon-Cheng")) goto again;
- if (substituteHyphen(g->players, "Hoyos-Millan")) goto again;
- if (substituteHyphen(g->players, "Ionescu-Ilie")) goto again;
- if (substituteHyphen(g->players, "Ivanka-Budinsky")) goto again;
- if (substituteHyphen(g->players, "Jan-Hein")) goto again;
- if (substituteHyphen(g->players, "Jan-Michel")) goto again;
- if (substituteHyphen(g->players, "Jan-Olav")) goto again;
- if (substituteHyphen(g->players, "Jan-Olov")) goto again;
- if (substituteHyphen(g->players, "Jan-Willem")) goto again;
- if (substituteHyphen(g->players, "Jean-Alexis")) goto again;
- if (substituteHyphen(g->players, "Jean-Claude")) goto again;
- if (substituteHyphen(g->players, "Jean-Luc")) goto again;
- if (substituteHyphen(g->players, "Jean-Marc")) goto again;
- if (substituteHyphen(g->players, "Jean-Philip")) goto again;
- if (substituteHyphen(g->players, "Jean-Pierre")) goto again;
- if (substituteHyphen(g->players, "Jean-Rene")) goto again;
- if (substituteHyphen(g->players, "Jean-Robert")) goto again;
- if (substituteHyphen(g->players, "Jens-Euw")) goto again;
- if (substituteHyphen(g->players, "Jens-Ove")) goto again;
- if (substituteHyphen(g->players, "Jens-Peter")) goto again;
- if (substituteHyphen(g->players, "Jens-Uwe")) goto again;
- if (substituteHyphen(g->players, "John-Paul")) goto again;
- if (substituteHyphen(g->players, "Juan-Pablo")) goto again;
- if (substituteHyphen(g->players, "Jukka-Pekka")) goto again;
- if (substituteHyphen(g->players, "Kai-Uwe")) goto again;
- if (substituteHyphen(g->players, "Kaj-Erik")) goto again;
- if (substituteHyphen(g->players, "Kari-Juhani")) goto again;
- if (substituteHyphen(g->players, "Karl-Heinz")) goto again;
- if (substituteHyphen(g->players, "Karl-Johan")) goto again;
- if (substituteHyphen(g->players, "Karl-Josef")) goto again;
- if (substituteHyphen(g->players, "Karl-Willi")) goto again;
- if (substituteHyphen(g->players, "Kick-Worthmuller")) goto again;
- if (substituteHyphen(g->players, "Kien-Hua")) goto again;
- if (substituteHyphen(g->players, "Klaus-Dieter")) goto again;
- if (substituteHyphen(g->players, "Klaus-Jurgen")) goto again;
- if (substituteHyphen(g->players, "Klimova-Richtrova")) goto again;
- if (substituteHyphen(g->players, "Kok-Siong")) goto again;
- if (substituteHyphen(g->players, "Lars-Ake")) goto again;
- if (substituteHyphen(g->players, "Lars-Bo")) goto again;
- if (substituteHyphen(g->players, "Lars-Erik")) goto again;
- if (substituteHyphen(g->players, "Lian-Ann")) goto again;
- if (substituteHyphen(g->players, "Litinskaya-Shul")) goto again;
- if (substituteHyphen(g->players, "Loheac-Amoun")) goto again;
- if (substituteHyphen(g->players, "M-Viorel")) goto again;
- if (substituteHyphen(g->players, "Macek-Kalchbrenner")) goto again;
- if (substituteHyphen(g->players, "Mads-Smith")) goto again;
- if (substituteHyphen(g->players, "Maki-Uuro")) goto again;
- if (substituteHyphen(g->players, "Maskova-Hajkova")) goto again;
- if (substituteHyphen(g->players, "Massoud-Amir")) goto again;
- if (substituteHyphen(g->players, "Meng-Kong")) goto again;
- if (substituteHyphen(g->players, "Mephisto-16")) goto again;
- if (substituteHyphen(g->players, "Mihai-Viorel")) goto again;
- if (substituteHyphen(g->players, "Mihail-Viorel")) goto again;
- if (substituteHyphen(g->players, "Milligan-Scott")) goto again;
- if (substituteHyphen(g->players, "Milner-Barry")) goto again;
- if (substituteHyphen(g->players, "Mircea-Sergiu")) goto again;
- if (substituteHyphen(g->players, "Mitaru-Serban")) goto again;
- if (substituteHyphen(g->players, "Neeraj-Kumar")) goto again;
- if (substituteHyphen(g->players, "Niels-Peter")) goto again;
- if (substituteHyphen(g->players, "Nils-Gus")) goto again;
- if (substituteHyphen(g->players, "Nils-Johan")) goto again;
- if (substituteHyphen(g->players, "Nokso-Koivisto")) goto again;
- if (substituteHyphen(g->players, "Nutu-Gajic")) goto again;
- if (substituteHyphen(g->players, "Ole-Christian")) goto again;
- if (substituteHyphen(g->players, "Peicheva-Hansen")) goto again;
- if (substituteHyphen(g->players, "Peicheva-Jurgens")) goto again;
- if (substituteHyphen(g->players, "Peitscheva-Hansen")) goto again;
- if (substituteHyphen(g->players, "Peitscheva-Jurgens")) goto again;
- if (substituteHyphen(g->players, "Per-Erik")) goto again;
- if (substituteHyphen(g->players, "Plauth-Herr")) goto again;
- if (substituteHyphen(g->players, "Popova-Lelchuk")) goto again;
- if (substituteHyphen(g->players, "Ralf-Axel")) goto again;
- if (substituteHyphen(g->players, "Renoy-Chevrier")) goto again;
- if (substituteHyphen(g->players, "Richtrova-Klimova")) goto again;
- if (substituteHyphen(g->players, "Rivas-Pastor")) goto again;
- if (substituteHyphen(g->players, "Sathe-Thipsay")) goto again;
- if (substituteHyphen(g->players, "Schmidt-Brauns")) goto again;
- if (substituteHyphen(g->players, "Shi-Lan")) goto again;
- if (substituteHyphen(g->players, "Sideif-Zade")) goto again;
- if (substituteHyphen(g->players, "Sieiro-Gonzalez")) goto again;
- if (substituteHyphen(g->players, "Sikora-Gizynska")) goto again;
- if (substituteHyphen(g->players, "Sikora-Lerch")) goto again;
- if (substituteHyphen(g->players, "Suan-Shiau")) goto again;
- if (substituteHyphen(g->players, "Tri-Sa-Ard")) goto again;
- if (substituteHyphen(g->players, "Tze-Meng")) goto again;
- if (substituteHyphen(g->players, "Veroci-Petronic")) goto again;
- if (substituteHyphen(g->players, "Victor-Angel")) goto again;
- if (substituteHyphen(g->players, "Videla-Seminara")) goto again;
- if (substituteHyphen(g->players, "Wagner-Michel")) goto again;
- if (substituteHyphen(g->players, "Weiss-Nowak")) goto again;
- if (substituteHyphen(g->players, "Wiese-Jozwiak")) goto again;
- if (substituteHyphen(g->players, "Znosko-Borovsky")) goto again;
- }
- return NULL;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node getBlackGame
- @deftypefun {char *} getBlackGame (Game @var{g})
- Returns the name of the player with the black pieces. The @w{@code{char
- *}} is allocated statically. A return value of @code{NULL} means that
- the information could not be extracted.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- char *
- getBlackGame(Game g)
- { static char black[MAX_NAME_SIZE+1];
- char *s;
-
- requireHeaderGame(g);
- s = strchr(g->players, '-');
- if (s && s == strrchr(g->players, '-'))
- { strcpy(black, ++s);
- return normalisePlayer(black);
- }
- return NULL;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node getNumberGame
- @deftypefun long getNumberGame (Game @var{g})
- Returns the number of the game (starting with 1) relative to the entire
- database.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- long
- getNumberGame(Game g)
- { requireHeaderGame(g);
- return g->number;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node getYearGame
- @deftypefun short getYearGame (Game @var{g})
- Returns the year the game was played. If the year is not known zero is
- returned.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- short
- getYearGame(Game g)
- { requireHeaderGame(g);
- return g->year;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node getEcoGame
- @deftypefun {char *} getEcoGame (Game @var{g})
- Returns the ECO (Encyclopedia of Chess Openings) code of the game.
- @code{NULL} is returned when the ECO code is not known.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- char *
- getEcoGame(Game g)
- { requireHeaderGame(g);
- if (g->eco[0])
- return g->eco;
- return NULL;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node getEcoMajorGame
- @deftypefun {char *} getEcoMajorGame (Game @var{g})
- Returns the ECO (Encyclopedia of Chess Openings) code of the game.
- @code{NULL} is returned when the ECO code is not known.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- char *
- getEcoMajorGame(Game g)
- { static char eco[4];
-
- requireHeaderGame(g);
- if (g->eco[0])
- { strncpy(eco, g->eco, 3);
- eco[3] = '\0';
- return eco;
- }
- return NULL;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node getFirstMoveGame
- @deftypefun Move getFirstMoveGame (Game @var{g})
- Returns the first move of the game.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- Move
- getFirstMoveGame(Game g)
- { requireMovesGame(g);
- return g->firstMove;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node getResultGame
- @deftypefun Result getResultGame (Game @var{g})
- Returns the result of game @var{g}. The result is @code{WHITE_WINS},
- @code{DRAW}, @code{BLACK_WINS} or one of the position evaluation codes
- (e.g. @code{WHITE_ADVANTAGE}). @code{NO_RESULT} is returned when the
- result is not known.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- Result
- getResultGame(Game g)
- { requireHeaderGame(g);
- return g->result;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node getRoundGame
- @deftypefun short getRoundGame (Game @var{g})
- Returns the round in which game @var{g} was played. The round is
- extracted from the source field using the heuristic that the round
- is between brackets (e.g @code{(15)}). The constant @code{NO_ROUND}
- is returned when the round could not be determined.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- short
- getRoundGame(Game g)
- { char *source;
- char *s;
- int round;
-
- requireHeaderGame(g);
- source = getSourceGame(g);
- for (s=source; *s; s++)
- { if (*s == '(' && isdigit(*(s+1)))
- { round = atoi(s+1);
- if (round > 0 && round < 40)
- return round;
- }
- }
- return NO_ROUND;
- }
-
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node checkHeaderGame
- @deftypefun bool checkHeaderGame (Game @var{g})
- Returns @code{FALSE} when decoding the header of the game resulted
- in an error and @code{TRUE} otherwise.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- bool
- checkHeaderGame(Game g)
- { requireHeaderGame(g);
- if (foundError())
- return FALSE;
- return TRUE;
- }
-
-
- short
- getMovesGame(Game g)
- { return g->moves;
- }
-
-
- short
- getEloWhiteGame(Game g)
- { return g->eloWhite;
- }
-
-
- short
- getEloBlackGame(Game g)
- { return g->eloBlack;
- }
-
-
- void
- printGame(Game g, FILE *fd)
- { TextBuffer tb;
- Position pos;
-
- tb = newTextBuffer(fd, 75);
-
- stringTextBuffer(tb, "GAME");
- formatSpaceTextBuffer(tb, "%ld", getNumberGame(g));
- if (getEcoGame(g))
- { stringSpaceTextBuffer(tb, "\"");
- stringTextBuffer(tb, getEcoGame(g));
- stringTextBuffer(tb, "\"");
- } else
- stringSpaceTextBuffer(tb, "\"\"");
- stringSpaceTextBuffer(tb, getPlayersGame(g));
- stringSpaceTextBuffer(tb, getSourceGame(g));
-
- if (getYearGame(g))
- formatSpaceTextBuffer(tb, "%d", getYearGame(g));
- stringNewlineTextBuffer(tb, "");
-
- pos = newPosition();
- if (!fullGameP(g))
- { copyPosition(pos, g->position);
- diagramPosition(pos, tb);
- }
-
- printMovesGame(g, getFirstMoveGame(g), pos, 0, 0, TRUE, tb);
-
- stringNewlineTextBuffer(tb, "SCORE ");
- if (getResultGame(g) != NO_RESULT)
- stringTextBuffer(tb, chessSymbol(getResultGame(g)));
-
- stringNewlineTextBuffer(tb, "\n");
- freeTextBuffer(tb);
- }
-
-
- void
- printMovesGame(Game g, /* Game we are printing */
- Move move, /* Move under consideration */
- Position pos, /* Position before ``move'' */
- int ply, /* Move number as a ply: 0.. */
- int level, /* Depth of variations: 0.. */
- int notation, /* SHORT/LONG_ALGEBRAIC */
- TextBuffer tb) /* Output TextBuffer */
- { int startPly = ply;
- bool printSpace = FALSE;
- bool printDots = TRUE;
- bool printNextDots = FALSE;
- bool marked = (level == 0 && markedGameP(g));
- int algebraic = (level == 0 ? SHORT_ALGEBRAIC : notation);
-
- if (marked && ply == 0)
- stringTextBuffer(tb, "\\begin{moves}");
-
- for (; move; move=move->next, ply++)
- { Position nextPos;
- bool comments = containsCommentsMoveP(move);
- bool variations = containsVariationsMoveP(move);
-
- if (printSpace)
- stringSpaceTextBuffer(tb, "");
- printSpace = TRUE;
-
- if (pos->toMove == WHITE)
- { formatTextBuffer(tb, "%d", (ply/2+1));
- stringTextBuffer(tb, chessSymbol(WHITE_MOVE_SYMBOL));
- } else
- { if (ply == startPly || printDots == TRUE)
- { formatTextBuffer(tb, "%d", (ply/2+1));
- stringTextBuffer(tb, chessSymbol(BLACK_MOVE_SYMBOL));
- }
- }
-
- if (variations)
- { nextPos = newPosition();
- copyPosition(nextPos, pos);
- } else
- { nextPos = NULL;
- }
-
- if (comments || variations || diagramMoveP(move))
- printNextDots = TRUE;
- else
- printNextDots = FALSE;
-
- outputMove(move, tb, pos, algebraic);
-
- if (marked && (comments || variations || diagramMoveP(move)))
- stringTextBuffer(tb, "\\end{moves}");
-
- if (comments || variations)
- { if (level == 0)
- stringSpaceTextBuffer(tb, chessSymbol(START_MAJOR_ALTERNATIVE));
- else
- stringSpaceTextBuffer(tb, chessSymbol(START_ALTERNATIVE));
- }
-
- if (comments)
- outputCommentsMove(move, tb, pos);
- doMovePosition(pos, move);
-
- if (variations)
- { if (comments)
- stringSpaceTextBuffer(tb, "");
- printMovesGame(g, move->alternative, nextPos, ply, level+1, algebraic, tb);
- }
-
- if (comments || variations)
- { if (level == 0)
- stringTextBuffer(tb, chessSymbol(END_MAJOR_ALTERNATIVE));
- else
- stringTextBuffer(tb, chessSymbol(END_ALTERNATIVE));
- }
-
- if (diagramMoveP(move) && !comments)
- { diagramPosition(pos, tb);
- printNextDots = TRUE;
- printSpace = FALSE;
- }
-
- if (marked && (comments || variations || diagramMoveP(move)))
- stringTextBuffer(tb, "\\begin{moves}");
-
- printDots = printNextDots;
- printNextDots = FALSE;
- }
-
- if (marked)
- stringTextBuffer(tb, "\\end{moves}");
-
- /*
- if (level == 1)
- stringTextBuffer(tb, chessSymbol(END_MAJOR_ALTERNATIVE));
- if (level > 1)
- stringTextBuffer(tb, chessSymbol(END_ALTERNATIVE));
- */
- freePosition(pos);
- }
-
-
- /*------------------------------------------------------------
- * Portable Game Notation
- *------------------------------------------------------------*/
-
- void
- pgnGame(Game g, FILE *fd, int notation)
- { TextBuffer tb;
- Position pos;
-
- if (!fullGameP(g))
- { fprintf(stderr, "Don't know how to print partial game (%ld) in PGN\n",
- g->number);
- return;
- }
-
- tb = newTextBuffer(fd, 75);
-
- formatTextBuffer(tb, "[Event \"%s\"]\n", getSourceGame(g));
- formatTextBuffer(tb, "[Site \"%s\"]\n", getSourceGame(g));
-
- if (getYearGame(g))
- formatTextBuffer(tb, "[Date \"%d\"]\n", getYearGame(g));
- else
- stringTextBuffer(tb, "[Date \"\"]\n");
-
- if (getRoundGame(g))
- formatTextBuffer(tb, "[Round \"%d\"]\n", getRoundGame(g));
- else
- stringTextBuffer(tb, "[Round \"\"]\n");
-
- if (getWhiteGame(g))
- formatTextBuffer(tb, "[White \"%s\"]\n", getWhiteGame(g));
- else
- stringTextBuffer(tb, "[White \"\"]\n");
-
- if (getBlackGame(g))
- formatTextBuffer(tb, "[Black \"%s\"]\n", getBlackGame(g));
- else
- stringTextBuffer(tb, "[Black \"\"]\n");
-
- if (getResultGame(g) != NO_RESULT)
- formatTextBuffer(tb, "[Result \"%s\"]\n", chessSymbol(getResultGame(g)));
- else
- stringTextBuffer(tb, "[Result \"\"]\n");
-
- stringTextBuffer(tb, "\n");
-
- pos = newPosition();
-
- pgnMovesGame(g, getFirstMoveGame(g), pos, 0, notation, tb);
-
- if (getResultGame(g) != NO_RESULT)
- stringSpaceTextBuffer(tb, chessSymbol(getResultGame(g)));
-
- stringNewlineTextBuffer(tb, "\n\n");
- freeTextBuffer(tb);
- }
-
-
- void
- pgnMovesGame(Game g, /* Game we are printing */
- Move move, /* Move under consideration */
- Position pos, /* Position before ``move'' */
- int ply, /* Move number as a ply (0..) */
- int notation, /* SHORT/LONG_ALGEBRAIC */
- TextBuffer tb) /* Output TextBuffer */
- { for (; move; move=move->next, ply++)
- { stringSpaceTextBuffer(tb, "");
-
- if (pos->toMove == WHITE)
- { formatTextBuffer(tb, "%d", (ply/2+1));
- stringTextBuffer(tb, chessSymbol(WHITE_MOVE_SYMBOL));
- }
-
- stringTextBuffer(tb, getStringMovePosition(pos, move, notation));
- doMovePosition(pos, move);
- }
- freePosition(pos);
- }
-
-
- /*------------------------------------------------------------
- * Status of a game
- *------------------------------------------------------------*/
-
- /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- @node bytesGame
- @deftypefun {unsigned long} bytesGame (Game @var{g})
- Returns the number of bytes game @var{g} occupies on disk. @code{NULL}
- is returned on an error.
- @end deftypefun
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
-
- unsigned long
- bytesGame(Game g)
- { if (g->flags & GAME_INIT_OK)
- { unsigned long bytes;
-
- g->cbGame = newCbGame();
- if ((bytes=readCbGame(g->cbGame, g->database, g->number)))
- { if (extractHeaderCbGame(g->cbGame, g))
- { g->flags |= GAME_HEADER_OK;
- return bytes;
- }
- freeCbGame(g->cbGame);
- g->cbGame = NULL;
- return (unsigned long) NULL;
- }
- freeCbGame(g->cbGame);
- g->cbGame = NULL;
- return (unsigned long) NULL;
- }
- if (g->cbGame)
- freeCbGame(g->cbGame);
- g->cbGame = NULL;
- return (unsigned long) NULL;
- }
-
-
- static void
- requireHeaderGame(Game g)
- { if (g->flags & GAME_HEADER_OK)
- return;
- if (g->flags & GAME_INIT_OK)
- { g->cbGame = newCbGame();
- if (readCbGame(g->cbGame, g->database, g->number))
- { if (extractHeaderCbGame(g->cbGame, g))
- { g->flags |= GAME_HEADER_OK;
- return;
- }
- freeCbGame(g->cbGame);
- g->cbGame = NULL;
- return;
- }
- freeCbGame(g->cbGame);
- g->cbGame = NULL;
- return;
- }
- if (g->cbGame)
- freeCbGame(g->cbGame);
- g->cbGame = NULL;
- }
-
-
- static void
- requireMovesGame(Game g)
- { if (g->flags & GAME_MOVES_OK)
- return;
- requireHeaderGame(g);
- if (g->cbGame)
- { if (extractMovesCbGame(g->cbGame, g))
- { g->flags |= GAME_MOVES_OK;
- return;
- }
- }
- }
-